using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//游戏面板
public class GameBroad : MonoBehaviour
{
    //使用默认值防止编译器警告
    [SerializeField]
    Transform ground = default;

    //使用整数的 2D 向量和点表示形式。
    Vector2Int size;

    //引用瓦片预制件
    [SerializeField]
    GameTile tilePrafab = default;

    //跟踪瓦片
    GameTile[] tiles;

    //搜索边界
    Queue<GameTile> searchFrontier = new Queue<GameTile>();

    //工厂引用
    GameTileContentFactory contentFactory;

    //是否显示路径
    bool showPaths;

    //网格纹理
    [SerializeField]
    Texture2D gridTexture = default;
    //是否显示网格纹理
    bool showGrid;

    //跟踪怪物出生点
    List<GameTile> spawnPoints = new List<GameTile>();

    //返回出生点数量
    public int SpawnPointCount =>spawnPoints.Count;

    //跟踪需要更新的内容
    List<GameTileContent> updatingContent = new List<GameTileContent>();
    
    public void Initialize(Vector2Int size, GameTileContentFactory contentFactory)
    {
        this.size = size;
        this.contentFactory = contentFactory;
        ground.localScale = new Vector3(size.x, size.y, 1f);

        //创建瓦片
        Vector2 offset = new Vector2((size.x - 1) * 0.5f, (size.y - 1) *0.5f);//必须使用浮点除法
        tiles = new GameTile[size.x * size.y];
        for(int i = 0,y = 0;y < size.y;y++)
        {
            for(int x = 0;x < size.x; x++,i++)
            {
                GameTile tile = tiles[i] = Instantiate(tilePrafab);//克隆并返回克隆对象
                tile.transform.SetParent(transform, false);
                tile.transform.localPosition = new Vector3(x - offset.x, 0f, y - offset.y );

                //建立邻居关系
                if(x > 0){
                    GameTile.MakeEastWestNeighbors(tile, tiles[i-1]);
                }
                if(y > 0){
                    GameTile.MakeNorthSouthNeighbors(tile, tiles[i-size.x]);
                }
                tile.IsAlternative = (x & 1) == 0;//如果x坐标为偶数，则为true
                if((y & 1) == 0){
                    tile.IsAlternative = !tile.IsAlternative;//如果Y坐标为偶数，则取反，产生棋盘格子图案
                }

            }
           
        }
        Clear();
    }

    //切换空瓦片和目的地瓦片
    public void ToggleDestination(GameTile tile)
    {
        if(tile.Content.Type == GameTileContentType.Destination){
            tile.Content = contentFactory.Get(GameTileContentType.Empty);
            if(!FindPaths()){
                tile.Content = contentFactory.Get(GameTileContentType.Destination);
                FindPaths();
            }
        }else if (tile.Content.Type == GameTileContentType.Empty) {
			tile.Content = contentFactory.Get(GameTileContentType.Destination);
			FindPaths();
		}
    }

    //切换墙体
    public void ToggleWall(GameTile tile)
    {
        //仅支持空瓦片和墙体之前的切换，不允许墙直接替换目的地。
        if(tile.Content.Type == GameTileContentType.Wall){
            tile.TileType = GameTileContentType.Empty;
            tile.Content = contentFactory.Get(GameTileContentType.Empty);
            FindPaths();
        }else if(tile.Content.Type == GameTileContentType.Empty){//仅当瓦片为空的时候，才能切换为墙体
            tile.Content = contentFactory.Get(GameTileContentType.Wall);
            tile.TileType = GameTileContentType.Wall;

            if(!FindPaths()){//墙体应该阻碍寻路，但是每个瓦片都需要有一条通往目的地的路径，如果没有则撤销更改
                tile.Content = contentFactory.Get(GameTileContentType.Empty);
                tile.TileType = GameTileContentType.Empty;
                FindPaths();
            }
        }
    }

    //切换怪物出生点
    public void ToggleSpawnPoint(GameTile tile)
    {
        if(tile.Content.Type == GameTileContentType.SpawnPoint){
            if(spawnPoints.Count > 1){
                spawnPoints.Remove(tile);
                tile.Content = contentFactory.Get(GameTileContentType.Empty);
            }
        }else if(tile.Content.Type == GameTileContentType.Empty){
            tile.Content = contentFactory.Get(GameTileContentType.SpawnPoint);
            spawnPoints.Add(tile);
        }
    }

    //切换塔
    public void ToggleTower(GameTile tile,TowerType towerType)
    {
        if(tile.Content.Type == GameTileContentType.Tower)
        {
            updatingContent.Remove(tile.Content);
            if(((Tower)tile.Content).TowerType == towerType){
                tile.Content = contentFactory.Get(GameTileContentType.Empty);
                FindPaths();
            }else{
                tile.Content = contentFactory.Get(towerType);
                updatingContent.Add(tile.Content);
            }
        }
        else if(tile.Content.Type == GameTileContentType.Empty)
        {
            tile.Content = contentFactory.Get(towerType);
            if(FindPaths())
            {
                updatingContent.Add(tile.Content);
            }else
            {
                tile.Content = contentFactory.Get(GameTileContentType.Empty);
                FindPaths();
            }
        }else if(tile.Content.Type == GameTileContentType.Wall)
        {
            tile.Content = contentFactory.Get(towerType);
            updatingContent.Add(tile.Content);
        }
    }

    //寻路
    bool FindPaths()
    {
       
        foreach(GameTile tile in tiles)
        {
        
            if(tile.Content.Type == GameTileContentType.Destination){
                tile.BecomeDestination();
                searchFrontier.Enqueue(tile);
            }else{
                tile.ClearPath();
            }
            
        }
        // tiles[tiles.Length / 2].BecomeDestination();
        // searchFrontier.Enqueue(tiles[tiles.Length / 2]);//向Queue的末尾添加一个对象

        if(searchFrontier.Count == 0)
            return false;
        while(searchFrontier.Count > 0)
        {
            //将单个瓦片移出边界，并扩大通向其邻居的路径，并将它们添加到边界上。
            //先向北，然后向东，然后向南，最后向西
            GameTile tile = searchFrontier.Dequeue();//移除并返回在Queue的开头的对象
            if(tile != null)
            {
                if(tile.IsAlternative){
                    searchFrontier.Enqueue(tile.GrowPathNorth());
                    searchFrontier.Enqueue(tile.GrowPathEast());
                    searchFrontier.Enqueue(tile.GrowPathSouth());
                    searchFrontier.Enqueue(tile.GrowPathWest());
                }else{
                    searchFrontier.Enqueue(tile.GrowPathWest());
                    searchFrontier.Enqueue(tile.GrowPathEast());
                    searchFrontier.Enqueue(tile.GrowPathSouth());
                    searchFrontier.Enqueue(tile.GrowPathNorth());
                }
                
            }
            
        }

        foreach(GameTile tile in tiles){
            if(!tile.HasPath){
                return false;//如果有瓦片没有路径走向目的地，则此次寻路无效
            }
        }
         
        if(showPaths)
        {
            foreach(GameTile tile in tiles)
            {
                tile.ShowPath();//显示寻路箭头
            }
        }
        

        return true;
        
    }

    //点击瓦片，即是投射射线
    public GameTile GetTile(Ray ray)
    {
        //如果射线有碰撞到任何碰撞体，返回true
        //RaycastHit用于从射线投射获取信息
        //maxDistance 射线最大距离
        //layerMask 指定只用的层
        if(Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, 1))
        {
            //使用撞击点的XZ位置来确定瓦片
            //通过将相关板的尺寸的一半加上集中点的坐标来获取瓦片坐标，然后将结果转换为整数
            int x = (int)(hit.point.x + size.x * 0.5f);
            int y = (int)(hit.point.z + size.y * 0.5f);
            if(x >= 0 && x < size.x && y >= 0 && y < size.y)
            {//瓦片坐标位于面板边界内
                //图块的索引为其X坐标加上其Y坐标乘以面板宽度。
                return tiles[x + y * size.x];
            }
            
        }
        return null;
    }

    //设置显示/隐藏路径
    public bool ShowPaths{
        get =>showPaths;
        set{
            showPaths = value;
            if(showPaths){
                foreach(GameTile tile in tiles){
                    tile.ShowPath();
                }
            }else{
                foreach(GameTile tile in tiles){
                    tile.HidePath();
                }
            }
        }
    }

    //显示网格
    public bool ShowGrid{
        get => showGrid;
        set{
            showGrid = value;
            Material m = ground.GetComponent<MeshRenderer>().material;
            if(showGrid){
                m.mainTexture = gridTexture;
                m.SetTextureScale("_MainTex", size);
            }else{
                m.mainTexture = null;
            }
        }
    }

    //访问出生点
    public GameTile GetSpawnPoint(int index)
    {
        return spawnPoints[index];
    }

    public void GameUpdate()
    {//更新
        for(int i = 0;i<updatingContent.Count;i++)
        {
            updatingContent[i].GameUpdate();
        }
    }

    public void Clear()
    {//清理回收
        foreach(GameTile tile in tiles)
        {
            tile.Content = contentFactory.Get(GameTileContentType.Empty);
        }
        spawnPoints.Clear();
        updatingContent.Clear();
        //设置目标点
        ToggleDestination(tiles[tiles.Length / 2]);
        //设置出生点
        ToggleSpawnPoint(tiles[0]);
    }
}
